/*
 *  Person.m
 *  pogostick
 *
 * This is the guy that you see shooting at the poor pogostick.
 *
 *  Created by daddy (chuck@kollar.com) on 8/26/09.
 *  Copyright 2009 Charles P. Kollar All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#import "Person.h"


@implementation Person


// I would try using a gear joint with a 1:1 ratio, a force maximum, and then animate the phase parameter of
// the joint. This will look much less springy and wavy. Beyond that, actually animating him... I have no idea,
// you are blazing new ground I think.

-(id)initInSpace:(cpSpace *)sp toStaticBody:(cpBody *)sb identifier:(NSString *)ident gravity:(cpFloat)gra group:(int)gro position:(cpVect)p size:(cpVect)size
{
    if (self = [super init])
    {
        [self setIdentifier:ident];
		[self setSpace:sp];
		[self setGravity:gra];
		[self setGroup:gro];
        
        [self setStickHeight:size.y*0.7f];
        [self setRiderMass:50.0f];
		
		blood = MAXBLOOD;
		
		cpFloat riderX = p.x, riderY=p.y;
		cpFloat initialStance = 5.0f;
        cpFloat bodyWidth = size.x * 0.25f;
		
		cpVect verts[] = {
			cpv(-bodyWidth,-stickHeight/2),
			cpv(-bodyWidth, stickHeight/2),
			cpv( bodyWidth, stickHeight/2),
			cpv( bodyWidth,-stickHeight/2),
		};
		
		trunkBody = cpBodyNew(riderMass, cpMomentForPoly(riderMass, (sizeof(verts)/sizeof(cpVect)), verts, cpvzero));
		trunkBody->p = cpv(riderX,riderY);
		cpSpaceAddBody(space, trunkBody);
		cpShape *shape = cpPolyShapeNew(trunkBody, (sizeof(verts)/sizeof(cpVect)), verts, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;// Don't collide objects in the same non-zero group
		cpSpaceAddShape(space, shape);
		
		// Attach the person to the static space so that they can stand.
		staticJoint = cpGearJointNew(sb, trunkBody, 0.0f, 1.0f);
		cpSpaceAddConstraint(space, staticJoint);
		
		cpFloat headRadius = size.x*0.4f;
		headBody = cpBodyNew(2.0f, cpMomentForCircle(2.0f, 0.0f, headRadius, cpvzero));
		headBody->p = cpv(riderX, riderY+stickHeight/2+headRadius);
		cpSpaceAddBody(space, headBody);
		shape = cpCircleShapeNew(headBody, headRadius, cpvzero);
		shape->e = 0.3f; shape->u = 2.5f;
		shape->group = group;
        shape->collision_type = kColl_Head;
        // need a pointer to the person so that we can kill them it they get hit in the head.
        // see the C function "footHitHeadEvent" in "ChipmunkPhys.m".
        shape->data = self;
		cpSpaceAddShape(space, shape);
		
		cpSpaceAddConstraint(space, cpPinJointNew(trunkBody, headBody, cpv(0.0f,stickHeight/2), cpv(0.0f,-headRadius)));
		// Gear Joint - Allows you to lock the rotation of two bodies together and set a ratio of their rotation rates.
		// Rotary servos: By using a gear joint with a 1:1 ratio, you lock the rotation of the two bodies together.
		// If you changed the rotary offset dynamically, the joint would quickly converge on the new value.
		// By setting a force maximum, you can at least stop it's movement if it gets jammed by something.
		// Now you can set the maximum convergence speed as well. If the joint is off by more than a certain amount,
		// it will correct itself using a linear speed.
		// A gear joint rotates from 0 - 2*pi radians, where 0 is down, pi is up, and pi/2 is to the right.
		neckJoint = cpGearJointNew(trunkBody, headBody, 0.0f, 1.0f);
		neckJoint->maxForce = MAX_JOINT_FORCE;
		cpSpaceAddConstraint(space, neckJoint);
        cpFloat armWidth = bodyWidth * 0.25f;
        
		cpVect verts2[] = {
			cpv(-armWidth,-stickHeight/4),
			cpv(-armWidth, stickHeight/4),
			cpv( armWidth, stickHeight/4),
			cpv( armWidth,-stickHeight/4),
		};
		
		legRUBody = cpBodyNew(1.0f, cpMomentForPoly(1.0f, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero));
		legRUBody->p = cpv(riderX-initialStance/2,riderY-stickHeight*3/4);
		cpSpaceAddBody(space, legRUBody);
		shape = cpPolyShapeNew(legRUBody, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;
		cpSpaceAddShape(space, shape);
		
		cpSpaceAddConstraint(space, cpPinJointNew(trunkBody, legRUBody, cpv(-2.0f,-stickHeight/2), cpv(2.0f,stickHeight/4)));
        // Doing two retains here to get it to work, and not sure why....
		rHipJoint = [[BodyJoint alloc] initInSpace: space trunkBody: trunkBody armBody: legRUBody right: 1];
		
		legRLBody = cpBodyNew(1.0f, cpMomentForPoly(1.0f, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero));
		legRLBody->p = cpv(riderX-initialStance/2,riderY-stickHeight*5/4);
		cpSpaceAddBody(space, legRLBody);
		shape = cpPolyShapeNew(legRLBody, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;
		cpSpaceAddShape(space, shape);
		
		cpSpaceAddConstraint(space, cpPinJointNew(legRUBody, legRLBody, cpv(0.0f,-stickHeight/4), cpv(0.0f,stickHeight/4)));
		rKneeJoint = [[BodyJoint alloc] initInSpace: space trunkBody: legRUBody armBody: legRLBody right: 1];
		
		legLUBody = cpBodyNew(1.0f, cpMomentForPoly(1.0f, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero));
		legLUBody->p = cpv(riderX+initialStance/2,riderY-stickHeight*3/4);
		cpSpaceAddBody(space, legLUBody);
		shape = cpPolyShapeNew(legLUBody, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;
		cpSpaceAddShape(space, shape);
		
		cpSpaceAddConstraint(space, cpPinJointNew(trunkBody, legLUBody, cpv(2.0f,-stickHeight/2), cpv(-2.0f,stickHeight/4)));
		lHipJoint = [[BodyJoint alloc] initInSpace: space trunkBody: trunkBody armBody: legLUBody right: 0];
		
		legLLBody = cpBodyNew(1.0f, cpMomentForPoly(1.0f, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero));
		legLLBody->p = cpv(riderX+initialStance/2,riderY-stickHeight*5/4);
		cpSpaceAddBody(space, legLLBody);
		shape = cpPolyShapeNew(legLLBody, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;
		cpSpaceAddShape(space, shape);
		
		cpSpaceAddConstraint(space, cpPinJointNew(legLUBody, legLLBody, cpv(0.0f,-stickHeight/4), cpv(0.0f,stickHeight/4)));
		lKneeJoint = [[BodyJoint alloc] initInSpace: space trunkBody: legLUBody armBody: legLLBody right: 0];
		
		armRUBody = cpBodyNew(1.0f, cpMomentForPoly(1.0f, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero));
		armRUBody->p = cpv(riderX-initialStance/2,riderY+stickHeight/4);
		cpSpaceAddBody(space, armRUBody);
		shape = cpPolyShapeNew(armRUBody, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;
		cpSpaceAddShape(space, shape);
		
		cpSpaceAddConstraint(space, cpPinJointNew(trunkBody, armRUBody, cpv(-2.0f,stickHeight/2), cpv(2.0f,stickHeight/4)));
		rSholderJoint = [[BodyJoint alloc] initInSpace: space trunkBody: trunkBody armBody: armRUBody right: 1];
		
		armRLBody = cpBodyNew(1.0f, cpMomentForPoly(1.0f, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero));
		armRLBody->p = cpv(riderX-initialStance/2,riderY-stickHeight/4);
		cpSpaceAddBody(space, armRLBody);
		shape = cpPolyShapeNew(armRLBody, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;
		cpSpaceAddShape(space, shape);

		cpSpaceAddConstraint(space, cpPinJointNew(armRUBody, armRLBody, cpv(0.0f,-stickHeight/4), cpv(0.0f,stickHeight/4)));
		rElbowJoint = [[BodyJoint alloc] initInSpace: space trunkBody: armRUBody armBody: armRLBody right: 1];
		
		armLUBody = cpBodyNew(1.0f, cpMomentForPoly(1.0f, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero));
		armLUBody->p = cpv(riderX+initialStance/2,riderY+stickHeight/4);
		cpSpaceAddBody(space, armLUBody);
		shape = cpPolyShapeNew(armLUBody, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;
		cpSpaceAddShape(space, shape);
		
		cpSpaceAddConstraint(space, cpPinJointNew(trunkBody, armLUBody, cpv(2.0f,stickHeight/2), cpv(-2.0f,stickHeight/4)));
		lSholderJoint = [[BodyJoint alloc] initInSpace: space trunkBody: trunkBody armBody: armLUBody right: 0];
		
		armLLBody = cpBodyNew(1.0f, cpMomentForPoly(1.0f, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero));
		armLLBody->p = cpv(riderX+initialStance/2,riderY-stickHeight/4);
		cpSpaceAddBody(space, armLLBody);
		shape = cpPolyShapeNew(armLLBody, (sizeof(verts2)/sizeof(cpVect)), verts2, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->group = group;
		cpSpaceAddShape(space, shape);
		
		cpSpaceAddConstraint(space, cpPinJointNew(armLUBody, armLLBody, cpv(0.0f,-stickHeight/4), cpv(0.0f,stickHeight/4)));
		lElbowJoint = [[BodyJoint alloc] initInSpace: space trunkBody: armLUBody armBody: armLLBody right: 1];
    }
    return self;
}

-(void) waveHandR {
}

// various joint rotations to make the person look like they are standing and shooting...
-(void) faceRight {
    [rSholderJoint rotate: -M_PI/8];
	[lSholderJoint rotate: M_PI/2];
	[rElbowJoint rotate: M_PI/8];
	[lHipJoint rotate: M_PI/8];
	[rHipJoint rotate: -M_PI/8];
	[lKneeJoint rotate: -M_PI/8];
	[rKneeJoint rotate: M_PI/8];
    shootingHand=1;
}

-(void) faceLeft {
    [lSholderJoint rotate: M_PI/8];
	[rSholderJoint rotate: -M_PI/2];
	[lElbowJoint rotate: -M_PI/8];
	[lHipJoint rotate: M_PI/8];
	[rHipJoint rotate: -M_PI/8];
	[lKneeJoint rotate: -M_PI/8];
	[rKneeJoint rotate: M_PI/8];
    shootingHand=2;
}

-(void) dealloc
{
	[super dealloc];
}

@end
